﻿/**
 * Copyright (c) 2008 Justin Etheredge http://www.codethinked.com
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Microsoft Public License (Ms-PL)
 * which accompanies this distribution, and is available at
 * http://www.opensource.org/licenses/ms-pl.html
 * If redistributing this code, this entire header must remain intact.
 * 
 * Some of the code in this application has been taken 
 * from the following sources (all of which are licensed under
 * the Ms-PL):
 * Matt Warren's Blog: http://blogs.msdn.com/mattwar/
 * MSDN: http://msdn2.microsoft.com/en-us/library/bb546158.aspx
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace LinqToSimpleDB
{
  public class Query<TData> : IOrderedQueryable<TData>
  {
    #region Properties

    private IQueryProvider _provider = null;

    public IQueryProvider Provider
    {
      get
      {
        return _provider;
      }
      private set
      {
        _provider = value;
      }
    }
    public Expression Expression { get; private set; }

    public Type ElementType
    {
      get { return typeof(TData); }
    }

    #endregion
    
    #region Constructors
    /// <summary>
    /// This constructor is called by the client to create the data source.
    /// </summary>
    public Query()
    {
      Provider = new SimpleDBQueryProvider();
      Expression = Expression.Constant(this);
    }

    /// <summary>
    /// This constructor is called by Provider.CreateQuery().
    /// </summary>
    /// <param name="expression"></param>
    public Query(SimpleDBQueryProvider provider)
    {
      if (provider == null)
      {
        throw new ArgumentNullException("provider");
      }

      Provider = provider;
      Expression = Expression.Constant(this);
    }

    /// <summary>
    /// This constructor is called by Provider.CreateQuery().
    /// </summary>
    /// <param name="expression"></param>
    public Query(SimpleDBQueryProvider provider, Expression expression)
    {
      if (provider == null)
      {
        throw new ArgumentNullException("provider");
      }

      if (expression == null)
      {
        throw new ArgumentNullException("expression");
      }

      if (!typeof(IQueryable<TData>).IsAssignableFrom(expression.Type))
      {
        throw new ArgumentOutOfRangeException("expression");
      }

      Provider = provider;
      Expression = expression;
    }
    #endregion

    #region Enumerators
    public IEnumerator<TData> GetEnumerator()
    {
      return (Provider.Execute<IEnumerable<TData>>(Expression)).GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      return (Provider.Execute<System.Collections.IEnumerable>(Expression)).GetEnumerator();
    }
    #endregion

    public string GetQueryText()
    {
      SimpleDBQueryProvider provider = (SimpleDBQueryProvider)this._provider;
      return provider.GetQueryText(this.Expression, provider.Precision, provider.Scale);
    }
  }
}
